package com.pig4cloud.pig.common.core.util;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;

/**
 * 随机工具类
 *
 * @Author: hjl
 * @Date: 2020/11/19 20:32
 */
@Slf4j
public class RandomUtils {

	/**
	 * 从数组中随机算出num个
	 * 限制：0 < num <= array.length
	 * 否则，返回空列表
	 * @param array
	 * @param num
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> randomSelected(T[] array, int num) {
		List<T> resultList = new ArrayList<>();
		if (array == null || num <= 0 || array.length< num) {
			return resultList;
		}
		// 获得一个该数组的复制
		T[] temp = Arrays.copyOf(array, array.length);
		int length = temp.length;
		int left = length;
		// length - left 为还需要计算多少次
		while (length - left < num) {
			// 随机选取一个元素，left 自减，这样不会覆盖上次产生的结果，并将下次选取的范围缩小
			int i = (int) Math.floor(Math.random() * left--);
			// 将被选中的数与数组的最后一位进行调换
			T tmp = temp[i];
			temp[i] = temp[left];
			temp[left] = tmp;
			resultList.add(tmp);
		}
		return resultList;
	}



	/**
	 * 均衡选择
	 * 从长度为l的列表list中取出m组长度为n的组合
	 * 1、每组内元素不重复
	 * 2、使得取出的元素的次数差不大于1
	 * 从数组中随机算出num个
	 * 限制：0 < n <= l     0 < m
	 */
	public static <T> List<Set<T>> uniformSelected(List<T> list, int m, int n) {
		List<Set<T>> resultList = new ArrayList<>();
		if (CollectionUtils.isEmpty(list) || n <= 0 || list.size() < n || m <= 0) {
			return resultList;
		}
		int l = list.size();
		// 循环生成各种组合
		for (int i = 0; i < m; i++) {
			Set<T> combination = new HashSet<>();

			// 生成第i种组合
			for (int j = 0; j < n; j++) {
				// 获取第j个元素
				// 位置
				int mod = i + j * m;
				T ele = list.get(mod % l);
				// 重复判断
				while (combination.contains(ele)) {
					mod++;
					ele = list.get(mod % l);
				}
				combination.add(ele);
			}

			if (!combination.isEmpty()) {
				resultList.add(combination);
			}
		}
		return resultList;
	}


	/**
	 *
	 * @param list 源列表
	 * @param m 组数
	 * @param n 每组元素个数
	 * @param <T>
	 * @return
	 */
	// 不重复随机分配
	public static <T> List<List<T>> randomEleListNoRepeat(List<T> list, int m, int n) {
		List<List<T>> resultList = new ArrayList<>();
		int needNum = m * n;
		List<T> randomList = RandomUtil.randomEleList(list, needNum);
		for (int i = 0; i< m; i++) {
			List<T> tmpList = new ArrayList<>();
			for (int j = 0; j< n; j++) {
				tmpList.add(randomList.get(i * n + j));
			}
			resultList.add(tmpList);
		}
		return resultList;
	}
	// 完全随机分配
	public static <T> List<List<T>> randomEleList(List<T> list, int m, int n) {
		List<List<T>> resultList = new ArrayList<>();
		for (int i = 0; i< m; i++) {
			List<T> tmpList = RandomUtil.randomEleList(list, n);
			resultList.add(tmpList);
		}
		return resultList;
	}

	public static void main(String[] args) {
//		Integer[] memberListByiDs = {1,2,3,4,5};
//		for (int i=0; i<10; i++) {
//			List randomList = randomSelected(memberListByiDs, 3);
//			log.info(JSON.toJSONString(randomList));
//		}


		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
//		List<Set<Integer>> sets = uniformSelected(list, 10, 3);
//		Map<Object, Integer> map = new HashMap<>();
//		for (Set<Integer> set : sets) {
//			for (Integer ele: set) {
//				if (!map.containsKey(ele)) {
//					map.put(ele, 1);
//				} else {
//					map.put(ele, map.get(ele)+1);
//				}
//			}
//		}
//		log.info(JSON.toJSONString(sets));
//		for(Map.Entry<Object, Integer> entry : map.entrySet()){
//			Object mapKey = entry.getKey();
//			Integer mapValue = entry.getValue();
//			log.info("{}, {}", mapKey, mapValue);
//		}



		int creativeSize = list.size();
		// 分配创意
		// 需要创意数 计划数 * 分配创意数
		int adNum = 7;
		int adCreativeNum = 2;
		int needNum = adNum * adCreativeNum;
		// 创意数 >= 需要创意数
		List<List<Integer>> adCreativesList;
		if (creativeSize >= needNum) {
			// 不重复随机分配
			adCreativesList = RandomUtils.randomEleListNoRepeat(list, adNum, adCreativeNum);
		} else {
			// 完全随机分配
			adCreativesList = RandomUtils.randomEleList(list, adNum, adCreativeNum);
		}

		Map<Object, Integer> map = new HashMap<>();
		for (List<Integer> list1 : adCreativesList) {
			for (Integer ele: list1) {
				if (!map.containsKey(ele)) {
					map.put(ele, 1);
				} else {
					map.put(ele, map.get(ele)+1);
				}
			}
		}
		log.info(JSON.toJSONString(adCreativesList));
		for(Map.Entry<Object, Integer> entry : map.entrySet()){
			Object mapKey = entry.getKey();
			Integer mapValue = entry.getValue();
			log.info("{}, {}", mapKey, mapValue);
		}

	}
}